package com.dingwen.minsta.service.impl;

import com.dingwen.minsta.config.DingwenMinioStarterProperties;
import com.dingwen.minsta.service.ClientService;
import com.dingwen.minsta.service.FileService;
import com.dingwen.minsta.task.TempCleanTask;
import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import io.minio.errors.*;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Optional;

/**
 * file service impl
 *
 * @author dingwen
 * 2021.05.27 17:31
 */
@Service
public class FileServiceImpl implements FileService {


    /**
     * 属性
     */
    private final DingwenMinioStarterProperties properties;

    /**
     * 清洁任务
     */
    private final TempCleanTask cleanTask;

    /**
     * minio客户端
     */
    private final MinioClient minioClient;

    @PostConstruct // 构造方法执行之前执行
    public void init() {
        if (properties.isTempCleanFlag()) {
            if (ObjectUtils.isEmpty(properties.getTempCleanFirstTime())) {
                cleanTask.clean(new Date(), properties.getTempCleanPeriod(), properties.getTempCleanDuration(), properties.getTempDir());
            } else {
                cleanTask.clean(properties.getTempCleanFirstTime(), properties.getTempCleanPeriod(), properties.getTempCleanDuration(), properties.getTempDir());
            }

        }
    }

    @Autowired
    public FileServiceImpl(ClientService clientService,
                           TempCleanTask cleanTask,
                           DingwenMinioStarterProperties properties) {
        this.properties = properties;
        this.cleanTask = cleanTask;

        minioClient = clientService.getClient(properties.getEndPoint(), properties.getAccessKey(), properties.getSecretKey());
    }

    @Override
    public boolean createBucket(String bucketName) {
        try {
            if (!minioClient.bucketExists(bucketName)) {
                minioClient.makeBucket(bucketName);
            }
            return true;
        } catch (ErrorResponseException | InsufficientDataException | InternalException
                | InvalidBucketNameException | InvalidKeyException | InvalidResponseException | IOException
                | NoSuchAlgorithmException | XmlParserException | RegionConflictException e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    public boolean removeBucket(String bucketName) {
        try {
            if (minioClient.bucketExists(bucketName)) {
                minioClient.removeBucket(bucketName);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public String saveFile(String bucketName, File file) {
        return saveFile(bucketName, file, null);
    }

    @Override
    public String saveFile(String bucketName, File file, String destinationFileName) {
        try {
            checkBucket(bucketName);
            if (!StringUtils.hasText(destinationFileName)) {
                destinationFileName = file.getName();
            }
            minioClient.putObject(bucketName, destinationFileName, file.getAbsolutePath(), new PutObjectOptions(new FileInputStream(file).available(), -1L));
            return destinationFileName;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public String saveFile(String bucketName, InputStream inputStream, String destinationFileName) {
        try {
            checkBucket(bucketName);
            Optional.ofNullable(destinationFileName).orElseThrow(() -> new RuntimeException("destinationFileName不能为空"));
            minioClient.putObject(bucketName, destinationFileName, inputStream, new PutObjectOptions(inputStream.available(),-1L));
            return destinationFileName;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public boolean removeFile(String fileName) {
        Optional.ofNullable(fileName).orElseThrow(() -> new RuntimeException("fileName不能为空"));
        return removeFile(properties.getBucket(), fileName);
    }

    @Override
    public boolean removeFile(String bucketName, String fileName) {
        Optional.ofNullable(bucketName).orElseThrow(() -> new RuntimeException("bucketName"));
        Optional.ofNullable(fileName).orElseThrow(() -> new RuntimeException("fileName不能为空"));
        try {
            minioClient.removeObject(bucketName,fileName);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public InputStream getStream(String fileName) {
        return getStream(properties.getBucket(), fileName);
    }

    @Override
    public InputStream getStream(String bucketName, String fileName) {
        Optional.ofNullable(fileName).orElseThrow(() -> new RuntimeException("fileName不能为空"));
        Optional.ofNullable(bucketName).orElseThrow(() -> new RuntimeException("bucketName不能为空"));
        try {
            return minioClient.getObject(bucketName, fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public File getFile(String fileName) {
        return getFile(fileName, properties.getBucket());
    }

    @Override
    public File getFile(String fileName, String bucketName) {
        Optional.ofNullable(fileName).orElseThrow(() -> new RuntimeException("fileName不能为空"));
        Optional.ofNullable(bucketName).orElseThrow(() -> new RuntimeException("bucketName不能为空"));
        InputStream inputStream = getStream(bucketName, fileName);
        File dir = new File(properties.getTempDir());
        if (!dir.exists() || dir.isFile()) {
            boolean flag = dir.mkdirs();
        }
        File file = new File(properties.getTempDir() + fileName);
        try {
            FileUtils.copyToFile(inputStream, file);
        } catch (IOException e) {
            e.printStackTrace();

        }
        return file;
    }

    @Override
    public void write(String fileName, OutputStream outputStream) {
        write(fileName, properties.getBucket(), outputStream);
    }

    @Override
    public void write(String fileName, String bucketName, OutputStream outputStream) {
        try {
            InputStream inputStream = getStream(bucketName, fileName);
            byte[] bytes = new byte[1024];
            int len;
            while ((len = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, len);
            }
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }


    /**
     * 检查桶
     *
     * @param bucketName bucket名称
     */
    public void checkBucket(String bucketName) throws Exception {
        Optional.ofNullable(bucketName).orElseThrow(() -> {
            String msg = "bucketName不能为空";
            return new RuntimeException(msg);
        });
        if (!minioClient.bucketExists(bucketName)) {
            minioClient.makeBucket(bucketName);
        }
    }
}
